import React, { useState, useEffect } from 'react';
import { GridLegacy as Grid } from '@mui/material';

/**
 * The adapter component provides a mechanism to group graphical components
 * that act as a single component when communicating to python.
 * This creates a 1-to-n mapping between the python variable and the
 * multiple js components.
 */

interface AdapterComponentProps {
  children: React.ReactElement[];
  value?: any;
  commands?: any[];
  convertFromPython?: (prevProps: any, prevState: any, value: any) => any;
  convertToPython?: (state: any) => any;
  onChange?: (event: any, index?: any, value?: any) => void;
  [key: string]: any;
}

interface AdapterState {
  [key: string]: string | number;
  lastUpdated?: string;
}

const AdapterComponent: React.FC<AdapterComponentProps> = ({
  children,
  value,
  commands,
  convertFromPython,
  convertToPython,
  onChange,
  ...otherProps
}) => {
  // Build initial state from children props
  const buildInitialState = (): AdapterState => {
    const stateBuilder: AdapterState = {};
    React.Children.forEach(children, (child) => {
      if (React.isValidElement(child) && child.props && typeof child.props === 'object' && 'id' in (child.props as object)) {
        stateBuilder[(child.props as any).id] = '';
      }
    });
    return stateBuilder;
  };

  const [state, setState] = useState<AdapterState>(buildInitialState);

  useEffect(() => {
    if (convertFromPython && value !== undefined) {
      const newValue = convertFromPython({}, state, value);
      if (newValue !== undefined) {
        setState(newValue);
      }
    }
  }, [value, commands, convertFromPython]);

  const handleChildChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    // Update State
    const newState = { ...state };
    let { value: inputValue } = event.target;
    
    if (inputValue === '') {
      inputValue = '0';
    } else if (isNaN(parseFloat(inputValue))) {
      return;
    }

    newState.lastUpdated = event.target.id;
    newState[event.target.id] = inputValue;
    setState(newState);

    // Call to conversion function
    if (convertToPython) {
      const newValue = convertToPython(newState);
      if (
        newValue !== undefined &&
        state.value !== newValue &&
        onChange
      ) {
        onChange(null, null, newValue);
      }
    }
  };

  const childrenWithExtraProp = React.Children.map(children, (child) => {
    if (React.isValidElement(child) && child.props && typeof child.props === 'object' && 'id' in (child.props as object)) {
      return React.cloneElement(child as React.ReactElement<any>, {
        onChange: handleChildChange,
        value: state[(child.props as any).id],
        ...otherProps,
      });
    }
    return child;
  });

  return (
    <Grid container spacing={1}>
      {childrenWithExtraProp && childrenWithExtraProp[0] && (
        <Grid item>{childrenWithExtraProp[0]}</Grid>
      )}
      {childrenWithExtraProp && childrenWithExtraProp[1] && (
        <Grid item>{childrenWithExtraProp[1]}</Grid>
      )}
    </Grid>
  );
};

export default AdapterComponent;

